from decimal import Decimal

from database import db_session

from models import *

from sqlalchemy import or_

from sqlalchemy.sql.expression import func
import managers.proyectos_mgr

def listar_proyectos_desarrollo(id_usuario):
    """Devuelve la lista de proyectos de los cuales el usuario 
    es miembro. Recibe como parametro el usuario
    @param id_usuario: El id del usuario logueado
    @return items: retorna la lista de proyectos"""
    
    usuario = db_session.query(Usuario).filter_by\
    (id_usuario=id_usuario).one()

    proyectos = usuario.proyectos

    items = []
    for proyecto in proyectos:
        item = dict(nombre=proyecto.nombre, descripcion=\
        proyecto.descripcion, observacion=proyecto.observacion, \
        estado=proyecto.estado, presupuesto=proyecto.presupuesto)
        items.append(item)

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def buscar_proyectos_desarrollo(id_usuario, cadena, campos):
    """Realiza la busqueda de proyectos de acuerdo al filtro seleccionado
    (nombre, descripcion, observacion, estado, presupuesto) y devuelve 
    las conincidencias encontradas
    @param id_usuario: El id del usuario logueado
    @param cadena: Cadena de caracteres que se busca en los registros 
    @param campos: Filtro utilizado para la busqueda
    @return items: retorna la lista con los datos buscados"""
    
    items = []
    presupuesto = None
    if campos == "todos":
        if cadena.isdecimal() == True:
            presupuesto = Decimal(cadena)

        proyectos = db_session.query(Proyecto).filter\
        (or_(func.lower(Proyecto.nombre).contains(cadena), \
        func.lower(Proyecto.descripcion).contains(cadena), \
        func.lower(Proyecto.observacion).contains(cadena), \
        func.lower(Proyecto.estado).contains(cadena), \
        Proyecto.presupuesto==presupuesto)).all()
    if campos == "nombre":
        proyectos = db_session.query(Proyecto).filter\
        (func.lower(Proyecto.nombre).contains(cadena)).all()
    if campos == "descripcion":
        proyectos = db_session.query(Proyecto).filter\
        (func.lower(Proyecto.descripcion).contains(cadena)).all()
    if campos == "observacion":
        proyectos = db_session.query(Proyecto).filter\
        (func.lower(Proyecto.observacion).contains(cadena)).all()
    if campos == "estado":
        proyectos = db_session.query(Proyecto).filter\
        (func.lower(Proyecto.estado).contains(cadena)).all()
    if campos == "presupuesto":
        if managers.proyectos_mgr.verificar_valor_presupuesto(cadena):
            presupuesto = Decimal(cadena)
            proyectos = db_session.query(Proyecto).filter\
            (Proyecto.presupuesto==presupuesto).all()
        else: #El valor no es un numero valido
            return items
            #Se retorna una lista vacia

    usuario = db_session.query(Usuario).filter_by\
    (id_usuario=id_usuario).one()

    for fila_proyecto in proyectos:
        for fila_proyecto_usuario in usuario.proyectos:
            if fila_proyecto.nombre == fila_proyecto_usuario.nombre:
                item = dict(nombre=fila_proyecto.nombre, descripcion=\
                fila_proyecto.descripcion, observacion=\
                fila_proyecto.observacion, estado=fila_proyecto.estado, \
                presupuesto=fila_proyecto.presupuesto)

                items.append(item)
                break

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items

def verificar_parametros_desarrollo_fases(seleccionados):
    """Verifica que se haya seleccionado un proyecto, y solo uno
    @param seleccionados: Lista de las fases seleccionadas
    @return error: retorna un mensaje de error en caso de no haber
                    seleccionadoni un proyecto o mas de un proyecto."""
    
    error = None

    if len(seleccionados) == 0: #No selecciono ningun proyecto
        error = "Debe seleccionar un proyecto"
        return error

    if len(seleccionados) > 1: #Selecciono mas de un proyecto
        error = "Debe seleccionar un solo proyecto"
        return error

    return error

def listar_fases_desarrollo(nombre_proyecto):
    """Devuelve la lista de fases del proyecto seleccionado. Recibe 
    como parametro el nombre del proyecto
    @param nombre_proyecto: Nombre del proyecto seleccionado
    @return items: retorna la lista de fases del proyecto"""
    
    proyecto = db_session.query(Proyecto).filter_by\
    (nombre=nombre_proyecto).one()

    fases = proyecto.fases

    items = []
    for fase in fases:
        item = dict(nombre=fase.nombre, descripcion=\
        fase.descripcion, observacion=fase.observacion, \
        estado=fase.estado, orden=fase.orden)
        items.append(item)

    items = sorted(items, key=lambda elemento: elemento['orden'])
    return items

def buscar_fases_desarrollo(nombre_proyecto, cadena, campos):
    """Realiza la busqueda de fases de acuerdo al filtro seleccionado
    (nombre, descripcion, observacion, estado, orden) y devuelve 
    las conincidencias encontradas
    @param nombre_proyecto: Nombre del proyecto seleccionado
    @param cadena: Cadena de caracteres que se busca en los registros 
    @param campos: Filtro utilizado para la busqueda
    @return items: retorna la lista con los datos buscados"""
    
    items = []
    orden = None

    proyecto = db_session.query(Proyecto).filter_by\
    (nombre=nombre_proyecto).one()

    if campos == "todos":
        try:
            orden = int(cadena)
        except:
            orden = None

        fases = db_session.query(Fase).filter_by(\
        fk_proyecto=proyecto.id).filter\
        (or_(func.lower(Fase.nombre).contains(cadena), \
        func.lower(Fase.descripcion).contains(cadena), \
        func.lower(Fase.observacion).contains(cadena), \
        func.lower(Fase.estado).contains(cadena), \
        Fase.orden==orden)).all()
    if campos == "nombre":
        fases = db_session.query(Fase).filter_by(\
        fk_proyecto=proyecto.id).filter\
        (func.lower(Fase.nombre).contains(cadena)).all()
    if campos == "descripcion":
        fases = db_session.query(Fase).filter_by(\
        fk_proyecto=proyecto.id).filter\
        (func.lower(Fase.descripcion).contains(cadena)).all()
    if campos == "observacion":
        fases = db_session.query(Fase).filter_by(\
        fk_proyecto=proyecto.id).filter\
        (func.lower(Fase.observacion).contains(cadena)).all()
    if campos == "estado":
        fases = db_session.query(Fase).filter_by(\
        fk_proyecto=proyecto.id).filter\
        (func.lower(Fase.estado).contains(cadena)).all()
    if campos == "orden":
        try:
            orden = int(cadena)
        except:
            return items

        fases = db_session.query(Fase).filter_by(\
        fk_proyecto=proyecto.id).filter(Fase.orden==orden).all()

    for fila_fase in fases:
        item = dict(nombre=fila_fase.nombre, descripcion=\
        fila_fase.descripcion, observacion=\
        fila_fase.observacion, estado=fila_fase.estado, \
        orden=fila_fase.orden)

        items.append(item)

    items = sorted(items, key=lambda elemento: elemento['orden'])
    return items

def verificar_parametros_desarrollo_tipoitem(seleccionados):
    """Verifica que se haya seleccionado una fase, y solo una
    @param seleccionados: Lista de tipo_item seleccionadas
    @return error: retorna un mensaje de error"""
    
    error = None

    if len(seleccionados) == 0: #No selecciono ninguna fase
        error = "Debe seleccionar una fase"
        return error

    if len(seleccionados) > 1: #Selecciono mas de una fase
        error = "Debe seleccionar una sola fase"
        return error

    return error

def listar_tipo_item(nombre_fase, nombre_proyecto):
    """Devuelve una lista con todos los tipos de items de la fase
    @param nombre_fase: indica el nombre de la fase
    @param nombre_proyecto: indica el nombre dl proyecto
    @return items: retorna la lista de tipos de items"""
    
    items = []

    proyecto = db_session.query(Proyecto).filter_by\
    (nombre=nombre_proyecto).one()

    fase = db_session.query(Fase).filter_by\
    (nombre=nombre_fase, fk_proyecto=proyecto.id).one()

    for tipoItem in fase.tipos_item:
        item = dict(id=tipoItem.id, nombre=tipoItem.nombre, \
        descripcion=tipoItem.descripcion, observacion=\
        tipoItem.observacion)
        items.append(item)

    items = sorted(items, key=lambda elemento: elemento['nombre'])
    return items
    
def listar_item(nombre_fase, nombre_proyecto):
    """Devuelve una lista con todos los items de la fase
    @param nombre_fase: indica el nombre de la fase
    @param nombre_proyecto: indica el nombre del proyecto
    @return items: retorna la lista de items"""
    
    lista_items = []

    proyecto = db_session.query(Proyecto).filter_by\
    (nombre=nombre_proyecto).one()

    fase = db_session.query(Fase).filter_by(fk_proyecto=proyecto.id).\
    filter_by(nombre=nombre_fase).one()

    tipos_item = db_session.query(TipoItem).filter_by(fk_fase=fase.id).\
    all()

    for tipoitem in tipos_item:
        items = db_session.query(Item).filter_by(\
        fk_tipo_item=tipoitem.id).all()
        for item in items:
            #Se omiten los items con estado Inactivo y Eliminado
            if item.estado != 'INA' and item.estado != 'ELI':
                elemento_item = dict(id=item.id, nombre=item.nombre,\
                descripcion=item.descripcion, observacion=item.observacion, \
                estado=item.estado, complejidad=item.complejidad, \
                costo=item.costo, tipo_item=tipoitem.nombre, \
                version=item.version)

                lista_items.append(elemento_item)

    lista_items = sorted(lista_items, key=lambda elemento: elemento['nombre'])
    return lista_items

def verificar_parametros_desarrollo_item(seleccionados):
    """Verifica que se haya seleccionado una fase, y solo una
    @param seleccionados: Lista de items seleccionados
    @return error: retorna un mensaje de error"""
    error = None

    if len(seleccionados) == 0: #No selecciono ninguna fase
        error = "Debe seleccionar una fase"
        return error

    if len(seleccionados) > 1: #Selecciono mas de una fase
        error = "Debe seleccionar una sola fase"
        return error

    return error

def verificar_parametros_desarrollo_linea_base(seleccionados):
    """Verifica que se haya seleccionado una fase, y solo una
    @param seleccionados: Lista de tipo_item seleccionadas
    @return error: retorna un mensaje de error"""
    error = None

    if len(seleccionados) == 0: #No selecciono ninguna fase
        error = "Debe seleccionar una fase"
        return error

    if len(seleccionados) > 1: #Selecciono mas de una fase
        error = "Debe seleccionar una sola fase"
        return error

    return error

def verificar_parametros_desarrollo_solicitud(seleccionados):
    """Verifica que se haya seleccionado un proyecto, y solo uno
    @param seleccionados: Lista de proyectos seleccionados"""
    error = None

    if len(seleccionados) == 0: #No selecciono ningun proyecto
        error = "Debe seleccionar un proyecto"
        return error

    if len(seleccionados) > 1: #Selecciono mas de un proyecto
        error = "Debe seleccionar un unico proyecto"
        return error

    return error

def verificar_parametros_ver_linea_base(seleccionados):
    """Verifica que se haya seleccionado una linea base, y solo una
    @param seleccionados: Lista de las lineas bases seleccionadas
    @return error: retorna un mensaje de error en caso de no haber
    seleccionado ni una linea base o mas de una linea base"""
    error = None

    if len(seleccionados) == 0: #No selecciono ninguna linea base
        error = "Debe seleccionar una linea base"
        return error

    if len(seleccionados) > 1: #Selecciono mas de una linea base
        error = "Debe seleccionar una unica linea base"
        return error

    return error
    
def validaciones_crear_grafo(seleccionados):
    
    error = None

    if len(seleccionados) == 0:
        error = "Debe seleccionar un proyecto"
        return error

    if len(seleccionados) > 1:
        error = "Debe seleccionar un solo proyecto"
        return error

    return error 
